
using System;
using System.Collections.Generic;
using System.Xml;
using Habazie.kf2.Core;
using Habazie.kf2.Roster;

namespace Habazie.kf2.Net
{
	
	
	public class IQManager
	{
		private Dictionary<string, jabber.client.IQHandler> m_handlers;
		
		public IQManager()
		{
			m_handlers = new Dictionary<string,jabber.client.IQHandler> ();
			
//			AddHandler ("jabber:iq:version"
			AddHandler ("http://jabber.org/protocol/disco#info", DiscoInfoHandler);
		}
		
		
		public void AddHandler (string ns, jabber.client.IQHandler handler)
		{
			m_handlers[ns] = handler;
		}
		
		
		public void RemoveNs (string ns)
		{
			m_handlers.Remove (ns);
		}
		
		
		public void Dispatch (Account acc, jabber.protocol.client.IQ iq)
		{
			XmlElement query = iq.Query;
			
			/* Check whether we know sender */
			try {
				Roster.Roster r = acc.GetRosterRef ();
				if (r.GetItem (iq.From) == null)
					/* Silently drop packet;-) */
					return;
			} catch (Exception e) {
				Util.ReportException (e);
				return; // something not good.
			}
				
			/* Check for registered handlers */
			if (query != null) {
				Util.Debug ("Net", "Dispatching <{0}>, ns={1}",
							query.LocalName, query.NamespaceURI);
				jabber.client.IQHandler handler = null;
				try {
					handler = m_handlers [query.NamespaceURI];
				} catch {
				}
				
				if (handler != null) {
					Gtk.Application.Invoke (delegate {
						handler (acc, iq);
					});
				} else {
					/* No handlers found */
					if (iq.Type != jabber.protocol.client.IQType.get && iq.Type != jabber.protocol.client.IQType.set)
						return;	// we should not respond to iq's other than get/set
					
					jabber.protocol.client.IQ response = new jabber.protocol.client.IQ (acc.Document);
					response.Type = jabber.protocol.client.IQType.error;
					response.ID = iq.ID;
					response.To = iq.From;
					jabber.protocol.client.Error error = new jabber.protocol.client.Error (acc.Document);
				//	error.Code = jabber.protocol.client.ErrorCode.NOT_IMPLEMENTED;
					error.SetAttribute ("type", "cancel");
					jabber.protocol.Element el = new jabber.protocol.Element (
												"feature-not-implemented",
												"urn:ietf:params:xml:ns:xmpp-stanzas",
												acc.Document);
					
					/* Add original query */
					response.AddChild (iq.Query);
					
					/* Add error messages */
					response.Error  = error;
					error.AddChild (el);
					
					acc.Write (response);
				}
			}
		}
		
		static jabber.protocol.client.IQ CreateResponse (Account acc, jabber.protocol.client.IQ iq)
		{
			jabber.protocol.client.IQ response = new jabber.protocol.client.IQ (acc.Document);
			response.Type = jabber.protocol.client.IQType.result;
			response.ID = iq.ID;
			response.To = iq.From;
			return response;
		}
		
		// Individual handlers
		private void DiscoInfoHandler (object o, jabber.protocol.client.IQ iq)
		{
			if (iq.Type != jabber.protocol.client.IQType.get)
				return;
				
			Account acc = o as Account;
			
			jabber.protocol.client.IQ response = IQManager.CreateResponse (acc, iq);
			jabber.protocol.iq.DiscoInfo query = new jabber.protocol.iq.DiscoInfo (acc.Document);
			jabber.protocol.iq.DiscoIdentity identity = query.AddIdentity (
							"client", "pc", "talkative");
			
			foreach (KeyValuePair<string, jabber.client.IQHandler> pair in m_handlers)
				query.AddFeature (pair.Key);
				
			response.AddChild (query);
			acc.Write (response);
		}
	}
}
